{
  Copyright 2012 Sergey Ostanin

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
}

unit SelectQuestionEditor;

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ActnList,
  ComCtrls, ExtCtrls, Shape, PadEditor, superobject, MiscUtils, ChoiceEditor,
  VisualUtils, QuestionEditors, Questions, SelectQuestion;

type
  TSelectQuestionEditorFrame = class(TShapeFrame, IQuestionEditor)
    actAddChoice: TAction;
    actDeleteChoice: TAction;
    actAddNegativeChoice: TAction;
    actFixChoice: TAction;
    actMoveChoiceDown: TAction;
    actMoveChoiceUp: TAction;
    alQuestion: TActionList;
    ilQuestion: TImageList;
    pnlQuestion: TPanel;
    sbxQuestion: TScrollBox;
    tbrQuestion: TToolBar;
    tbAddChoice: TToolButton;
    tbDeleteChoice: TToolButton;
    tbSeparator1: TToolButton;
    tbMoveChoiceUp: TToolButton;
    tbMoveChoiceDown: TToolButton;
    tbSeparator2: TToolButton;
    tbAddNegativeChoice: TToolButton;
    tbFixChoice: TToolButton;
    procedure actAddChoiceExecute(Sender: TObject);
    procedure actAddNegativeChoiceExecute(Sender: TObject);
    procedure actDeleteChoiceExecute(Sender: TObject);
    procedure actDeleteChoiceUpdate(Sender: TObject);
    procedure actFixChoiceExecute(Sender: TObject);
    procedure actFixChoiceUpdate(Sender: TObject);
    procedure actMoveChoiceDownExecute(Sender: TObject);
    procedure actMoveChoiceDownUpdate(Sender: TObject);
    procedure actMoveChoiceUpExecute(Sender: TObject);
    procedure actMoveChoiceUpUpdate(Sender: TObject);
  private
    FFormulation: TPadEditorFrame;
    FChoices: TChoiceEditorFrameList;
    FSelectChoice: Integer;
    FOldChoiceEditorIds: UnicodeString;
    procedure SyncChoiceEditors;
    function SelectedChoiceIndex: Integer;
    function SelectedChoice: TChoiceEditorFrame;
    procedure MoveChoice(Down: Boolean);
    { private declarations }
  public
    procedure AfterConstruction; override;
    destructor Destroy; override;
    procedure Render;
    { public declarations }
  end; 

implementation

{$R *.lfm}
{$R *.rc}

resourcestring
  SSelectQuestion = 'Multiple Choice Question';

{ TSelectQuestionEditorFrame }

procedure TSelectQuestionEditorFrame.actAddChoiceExecute(Sender: TObject);
begin
  Dispatcher.PerformAction(Id, 'addChoice');
  FSelectChoice := FChoices.Count;
end;

procedure TSelectQuestionEditorFrame.actAddNegativeChoiceExecute(Sender: TObject);
var
  Input: ISuperObject;
begin
  Input := SO;
  Input.S['text'] := TSelectQuestion.DefaultNegativeChoiceText;
  Dispatcher.PerformAction(Id, 'addNegativeChoice', Input);

  FSelectChoice := FChoices.Count;
end;

procedure TSelectQuestionEditorFrame.actDeleteChoiceExecute(Sender: TObject);
var
  Index: Integer;
  Input: ISuperObject;
begin
  Index := SelectedChoiceIndex;

  Input := SO;
  Input.I['choiceIndex'] := Index;
  Dispatcher.PerformAction(Id, 'deleteChoice', Input);

  if Index = FChoices.Count-1 then
    FSelectChoice := Index-1
  else
    FSelectChoice := Index;
end;

procedure TSelectQuestionEditorFrame.actDeleteChoiceUpdate(Sender: TObject);
begin
  (Sender as TAction).Enabled := SelectedChoiceIndex <> -1;
end;

procedure TSelectQuestionEditorFrame.actFixChoiceExecute(Sender: TObject);
var
  Choice: TChoiceEditorFrame;
begin
  Choice := SelectedChoice;
  Choice.SetFixed(not Choice.Fixed);
end;

procedure TSelectQuestionEditorFrame.actFixChoiceUpdate(Sender: TObject);
var
  Choice: TChoiceEditorFrame;
begin
  Choice := SelectedChoice;
  if Choice = nil then
  begin
    (Sender as TAction).Enabled := FALSE;
    (Sender as TAction).Checked := FALSE;
  end
  else
  begin
    (Sender as TAction).Enabled := TRUE;
    (Sender as TAction).Checked := Choice.Fixed;
  end;
end;

procedure TSelectQuestionEditorFrame.actMoveChoiceDownExecute(Sender: TObject);
begin
  MoveChoice(TRUE);
end;

procedure TSelectQuestionEditorFrame.actMoveChoiceDownUpdate(Sender: TObject);
var
  ChoiceIndex: Integer;
begin
  ChoiceIndex := SelectedChoiceIndex;
  (Sender as TAction).Enabled := (ChoiceIndex <> -1) and (ChoiceIndex < FChoices.Count - 1);
end;

procedure TSelectQuestionEditorFrame.actMoveChoiceUpExecute(Sender: TObject);
begin
  MoveChoice(FALSE);
end;

procedure TSelectQuestionEditorFrame.actMoveChoiceUpUpdate(Sender: TObject);
begin
  (Sender as TAction).Enabled := SelectedChoiceIndex > 0;
end;

procedure TSelectQuestionEditorFrame.SyncChoiceEditors;
var
  Ids, Id: ISuperObject;
begin
  Ids := Shape['choiceEditor'];
  if AssignDiffering(Ids.AsJSon, FOldChoiceEditorIds) then
  begin
    FChoices.Clear;
    for Id in Ids do
      FChoices.AddSafely(TChoiceEditorFrame.Create(Id.AsString, Dispatcher, pnlQuestion));
  end;
end;

function TSelectQuestionEditorFrame.SelectedChoiceIndex: Integer;
begin
  for Result := 0 to FChoices.Count-1 do
    if ContainsActiveFormControl(FChoices[Result]) then
      Exit;
  Result := -1;
end;

function TSelectQuestionEditorFrame.SelectedChoice: TChoiceEditorFrame;
var
  Index: Integer;
begin
  Index := SelectedChoiceIndex;
  if Index = -1 then
    Result := nil
  else
    Result := FChoices[Index];
end;

procedure TSelectQuestionEditorFrame.MoveChoice(Down: Boolean);
var
  Input: ISuperObject;
begin
  Input := SO;
  Input.I['choiceIndex'] := SelectedChoiceIndex;
  Input.B['forward'] := Down;
  Dispatcher.PerformAction(Id, 'moveChoice', Input);
end;

procedure TSelectQuestionEditorFrame.AfterConstruction;
begin
  inherited;
  alQuestion.OnExecute := Scene.ActionListExecuteFilter;
  LoadActionImages(alQuestion);
  MakeVerticallyAutoScrollable(sbxQuestion);

  FFormulation := TPadEditorFrame.Create(Shape.S['formulationEditor'], Dispatcher, pnlQuestion);
  FFormulation.Border := TRUE;

  FChoices := TChoiceEditorFrameList.Create;
  FSelectChoice := -1;
end;

destructor TSelectQuestionEditorFrame.Destroy;
begin
  FreeAndNil(FFormulation);
  FreeAndNil(FChoices);
  inherited;
end;

procedure TSelectQuestionEditorFrame.Render;
var
  Choice: TChoiceEditorFrame;
begin
  UpdateShape;

  DisableAutoSizing;
  try
    FFormulation.Render;
    SyncChoiceEditors;
    for Choice in FChoices do
      Choice.Render;
  finally
    EnableAutoSizing;
  end;

  if (FSelectChoice >= 0) and (FSelectChoice < FChoices.Count) then
    FChoices[FSelectChoice].SelectFirst;
  FSelectChoice := -1;

  actAddChoice.Enabled := Shape.B['canAddChoice'];
  actAddNegativeChoice.Enabled := Shape.B['canAddNegativeChoice'];
end;

initialization

  QuestionRegistry.Add(TSelectQuestion.Kind, SSelectQuestion, 'SelectQuestionEditor/selectQuestion.png', '');
  QuestionEditorRegistry.Add(TSelectQuestionEditorFrame, $21db1a5fa1bb12fa);

end.

